﻿using LettuceEncrypt;
using LettuceEncrypt.Accounts;
using LettuceEncrypt.Acme;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Quickly.Certs.AliDns;
using Quickly.Certs.Core.LettuceEncrypt;
using Quickly.Certs.LettuceEncrypt;

namespace Quickly.Certs.Core
{
    public static class BuilderExtensions
    {
        /// <summary>
        /// 证书质询相关内容
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configure"></param>
        /// <returns></returns>
        public static ILettuceEncryptServiceBuilder AddCertsCoreQuickly(this IServiceCollection services, Action<LettuceEncryptOptions>? configure = null)
        {
            var builder = services.AddLettuceEncrypt(options =>
            {
                configure?.Invoke(options);
                options.AllowedChallengeTypes = ChallengeType.Dns01;    // 仅允许Dns01
            });

            // 替换Dns01
            services.Replace(ServiceDescriptor.Singleton(typeof(IDnsChallengeProvider), typeof(Dns01ChallengeProvider)));
            services.AddScoped<AlibabaCloudDnsClient>();

            services.AddTransient<ICertificateRepository, DatabaseCertificateRepository>();

            return builder;
        }

        /// <summary>
        /// 证书持久化内容
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="configuration"></param>
        /// <param name="configure"></param>
        /// <returns></returns>
        public static ILettuceEncryptServiceBuilder AddCertsPersistence(this ILettuceEncryptServiceBuilder builder, IConfiguration configuration, Action<CertsPersistenceOptions>? configure = null)
        {
            var section = configuration.GetSection("CertsPersistence");

            var option = new CertsPersistenceOptions();
            section?.Bind(option);
            configure?.Invoke(option);

            builder.Services.AddTransient<IConfigureOptions<CertsPersistenceOptions>>(sp =>
            {
                var cfg = sp.GetService<IConfiguration?>();
                return new ConfigureOptions<CertsPersistenceOptions>(options => cfg?.Bind("CertsPersistence", options));
            });

            builder.Services.AddTransient<IConfigureOptions<DirectoryCertsPersistenceOptions>>(sp =>
            {
                var cfg = sp.GetService<IConfiguration?>();
                return new ConfigureOptions<DirectoryCertsPersistenceOptions>(options => cfg?.Bind("CertsPersistence", options));
            });

            switch (option.StorageType)
            {
                case CertsPersistenceType.Directory:
                    var directoryOptions = new DirectoryCertsPersistenceOptions();
                    section?.Bind(directoryOptions);

                    builder.PersistDataToDirectory(new DirectoryInfo(directoryOptions.Path), directoryOptions.PfxPassword);

                    break;
                case CertsPersistenceType.Database:

                    builder.Services.AddSingleton<ICertificateRepository, DatabaseCertificateRepository>();
                    builder.Services.AddSingleton<ICertificateSource, DatabaseCertificateRepository>();
                    
                    builder.Services.AddSingleton<IAccountStore, DatabaseAccountStore>();

                    break;
                case CertsPersistenceType.None:
                default:
                    break;
            }

            return builder;
        }
    }
}
